package cn.good.yan.service.t11;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * 11.AQS
 * StampedLock 读写锁的升级 （邮戳锁） - 传统版本的 - 跟ReentrantReadWriteLock一样
 * StampedLock = ReentrantReadWriteLock + 读的过程中也允许获取写锁介入
 * 【这个就是，写锁，正在写，但没有写完，释放锁， 读锁就被卡主，等待写锁的释放，读写互斥，有写锁饥饿问题】
 *
 * @author shengren.yan
 * @create 2024-04-10
 */
public class StampedLockDemo1 {
    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    // 写锁
    public void write() {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程准备修改");
        try {
            number = number + 13;
        } finally {
            stampedLock.unlockWrite(stamp);
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "写线程结束修改");
    }

    // 悲观读，读没有完成时候写锁无法获得锁
    public void read() {
        long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName() + "\t" + " 正在读-开始...");
        for (int i = 0; i < 4; i++) {
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取中......");
        }

        try {
            int result = number;
            System.out.println(Thread.currentThread().getName() + "\t" + " 获得成员变量值result：" + result);
            System.out.println("写线程没有修改成功，读锁时候写锁无法介入，传统的读写互斥");
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    public static void main(String[] args) {
        StampedLockDemo1 resource = new StampedLockDemo1();

        // 传统版 - 先读
        new Thread(() -> {
            resource.read(); // 读
        }, "readThread").start();

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t" + "----come in");
            resource.write();  // 写
        }, "writeThread").start();

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + "number:" + number);

    }
}
